package functionTypes;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.Random;
import java.util.StringTokenizer;

import Abstracts.AbstractFunction;
import Abstracts.AbstractGeneticFunction;
import Abstracts.AbstractSinglePropertyFunction;

public class ConstantSampling implements AbstractGeneticFunction, Cloneable {

	public AbstractSinglePropertyFunction[] subfunctions;
	int samplesCount = 200;
	double leftBorder = 20;
	double rightBorder = 100;

	public ConstantSampling clone() throws CloneNotSupportedException {
		ConstantSampling obj = (ConstantSampling) super.clone();
		obj.subfunctions = new AbstractSinglePropertyFunction[subfunctions.length];
		for (int i = 0; i != subfunctions.length; ++i) {
			obj.subfunctions[i] = subfunctions[i].clone();
		}
		obj.samplesCount = samplesCount;
		obj.leftBorder = leftBorder;
		obj.rightBorder = rightBorder;
		return obj;
	}

	/*
	 * public void clone(AbstractFunction f){ f = new ConstantSampling();
	 * AbstractSinglePropertyFunction[] subs = new
	 * AbstractSinglePropertyFunction[this.subfunctions.length]; for (int
	 * i=0;i!=subs.length;++i){ subfunctions[i].clone(subs[i]); }
	 * f.createAbstractFunction(subs); ((ConstantSampling)f).samplesCount =
	 * this.samplesCount; ((ConstantSampling)f).leftBorder = this.leftBorder;
	 * ((ConstantSampling)f).rightBorder = this.rightBorder; }
	 */

	public void setBorders(double left, double right) throws Exception {
		if (left < right) {
			leftBorder = left;
			rightBorder = right;
		} else {
			throw new Exception("Left border shoud be lower than right");
		}
	}

	public ConstantSampling() {
		generateFunction();
	}

	public void bigMutate() {
		generateFunction();
	}

	public void mutate(double chance) {

		Random random = new Random();
		for (int i = 0; i != subfunctions.length; ++i) {
			double d = Math.max(Math.min(subfunctions[i]
					.getCoeff()[0]
					+ random.nextGaussian()/4, 1), 0);
			if (d!=0)
				if (d!=1)
					subfunctions[i].getCoeff()[0] = d;
		}
		/*
		 * 
		 * for (int i = 0; i != subfunctions.length; ++i) { if (Math.random() <
		 * chance) subfunctions[i].getCoeff()[0] = Math.random(); }
		 */

	}

	public double compute(double[] params) {
		double step = (rightBorder - leftBorder) / samplesCount;
		int sampleIndex = (int) (Math.abs((params[0] - leftBorder) / step));
		if (sampleIndex == samplesCount)
			--sampleIndex;
		return subfunctions[sampleIndex].getCoeff()[0];
	}

	public void createAbstractFunction(AbstractSinglePropertyFunction[] args) {
		subfunctions = args;
	}

	public void generateFunction() {
		subfunctions = new OldSinglePropertyFunction[samplesCount];
		for (int i = 0; i != subfunctions.length; ++i) {
			subfunctions[i] = new OldSinglePropertyFunction();
			subfunctions[i].setConstantType();
		}
	}

	public ConstantSampling[] crossover(ConstantSampling f)
			throws CloneNotSupportedException {
		ConstantSampling new1 = new ConstantSampling();
		ConstantSampling new2 = new ConstantSampling();
		int beginIndex1 = (int) (Math.random() * (samplesCount / 2));
		int beginIndex2 = (int) (Math.random() * (samplesCount / 2));
		int length = (int) (Math.random() * samplesCount / 4 + samplesCount / 4);
		int endIndex1 = beginIndex1 + length - 1;
		int endIndex2 = beginIndex2 + length - 1;

		for (int i = 0; i != subfunctions.length; ++i) {
			new1.subfunctions[i] = null;
			new2.subfunctions[i] = null;
		}

		int k = 0;

		for (int i = beginIndex1; i != endIndex1; ++i) {
			new1.subfunctions[i] = f.subfunctions[beginIndex2 + k].clone();
			++k;
		}

		k = 0;

		for (int i = beginIndex2; i != endIndex2; ++i) {
			new2.subfunctions[i] = subfunctions[beginIndex1 + k].clone();
			++k;
		}

		for (int i = 0; i != subfunctions.length; ++i) {
			if (new1.subfunctions[i] == null) {
				new1.subfunctions[i] = subfunctions[i].clone();
			}
			if (new2.subfunctions[i] == null) {
				new2.subfunctions[i] = f.subfunctions[i].clone();
			}
		}
		return new ConstantSampling[] { this, f, new1, new2 };
	}

	public AbstractSinglePropertyFunction[] getSubFunctions() {
		return subfunctions;
	}

}
